#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;

class segment_tree {
	vector<int> &arr;

	vector<int> sum;
	vector<int> update;
	vector<bool> isupdate;

	vector<int> len;
	vector<int> pre;
	vector<int> suf;
	vector<int> zlen;
	vector<int> zpre;
	vector<int> zsuf;
	vector<bool> revers;

	void lazyupdate(int i, int v, int n)
	{
		sum[i] = v == 1 ? n : 0;
		len[i] = pre[i] = suf[i] = v == 1 ? n : 0;
		zlen[i] = zpre[i] = zsuf[i] = v == 0 ? n : 0;
		update[i] = v;
		isupdate[i] = true;
		revers[i] = false;
	}

	void lazyrevers(int i, int n)
	{
		sum[i] = n - sum[i];
		swap(len[i], zlen[i]);
		swap(pre[i], zpre[i]);
		swap(suf[i], zsuf[i]);
		revers[i] = !revers[i];
	}

	void up(int i, int ln, int rn)
	{
		int l = i << 1;
		int r = i << 1 | 1;

		sum[i] = sum[l] + sum[r];

		len[i] = max({ len[l], len[r], suf[l] + pre[r] });
		pre[i] = sum[l] == ln ? pre[l] + pre[r] : pre[l];
		suf[i] = sum[r] == rn ? suf[l] + suf[r] : suf[r];

		zlen[i] = max({ zlen[l], zlen[r], zsuf[l] + zpre[r] });
		zpre[i] = sum[l] == 0 ? zpre[l] + zpre[r] : zpre[l];
		zsuf[i] = sum[r] == 0 ? zsuf[l] + zsuf[r] : zsuf[r];
	}

	void down(int i, int ln, int rn)
	{
		if (isupdate[i]) {
			lazyupdate(i << 1, update[i], ln);
			lazyupdate(i << 1 | 1, update[i], rn);
			isupdate[i] = false;
		}

		if (revers[i]) {
			lazyrevers(i << 1, ln);
			lazyrevers(i << 1 | 1, rn);
			revers[i] = false;
		}
	}

	void build(int l, int r, int i)
	{
		if (l == r) {
			sum[i] = arr[l];
			len[i] = pre[i] = suf[i] = arr[l];
			zlen[i] = zpre[i] = zsuf[i] = arr[l] == 1 ? 0 : 1;
		} else {
			int mid = (l + r) >> 1;
			build(l, mid, i << 1);
			build(mid + 1, r, i << 1 | 1);
			up(i, mid - l + 1, r - mid);
		}
		revers[i] = false;
		isupdate[i] = false;
		update[i] = 0;
	}

    public:
	segment_tree(int n, vector<int> &arr)
		: arr(arr), sum(n << 2, 0), len(n << 2, 0), pre(n << 2, 0), suf(n << 2, 0), zlen(n << 2, 0), zpre(n << 2, 0), zsuf(n << 2, 0), update(n << 2, 0),
		  isupdate(n << 2, false), revers(n << 2, false)
	{
		build(1, n, 1);
	}

	void reset(int jobl, int jobr, int v, int l, int r, int i)
	{
		if (jobl <= l && r <= jobr) {
			lazyupdate(i, v, r - l + 1);
		} else {
			int mid = (l + r) >> 1;
			down(i, mid - l + 1, r - mid);
			if (jobl <= mid) {
				reset(jobl, jobr, v, l, mid, i << 1);
			}
			if (mid < jobr) {
				reset(jobl, jobr, v, mid + 1, r, i << 1 | 1);
			}
			up(i, mid - l + 1, r - mid);
		}
	}

	void reversex(int jobl, int jobr, int l, int r, int i)
	{
		if (jobl <= l && r <= jobr) {
			lazyrevers(i, r - l + 1);
		} else {
			int mid = (l + r) >> 1;
			down(i, mid - l + 1, r - mid);
			if (jobl <= mid) {
				reversex(jobl, jobr, l, mid, i << 1);
			}
			if (mid < jobr) {
				reversex(jobl, jobr, mid + 1, r, i << 1 | 1);
			}
			up(i, mid - l + 1, r - mid);
		}
	}

	int query_sum(int jobl, int jobr, int l, int r, int i)
	{
		if (jobl <= l && r <= jobr) {
			return sum[i];
		} else {
			int mid = (l + r) >> 1;
			down(i, mid - l + 1, r - mid);
			int res = 0;
			if (jobl <= mid) {
				res += query_sum(jobl, jobr, l, mid, i << 1);
			}
			if (mid < jobr) {
				res += query_sum(jobl, jobr, mid + 1, r, i << 1 | 1);
			}
			return res;
		}
	}

	int query_maxlen(int jobl, int jobr, int l, int r, int i)
	{
		if (jobl <= l && r <= jobr) {
			return len[i];
		} else {
			int mid = (l + r) >> 1;
			down(i, mid - l + 1, r - mid);
			if (jobr <= mid) {
				return query_maxlen(jobl, jobr, l, mid, i << 1);
			} else if (mid < jobl) {
				return query_maxlen(jobl, jobr, mid + 1, r, i << 1 | 1);
			} else {
				return max({ //
					     query_maxlen(jobl, jobr, l, mid, i << 1), //
					     query_maxlen(jobl, jobr, mid + 1, r, i << 1 | 1), //
					     min(suf[i << 1], mid - jobl + 1) + min(pre[i << 1 | 1], jobr - mid) });
			}
		}
	}
};

int main()
{
	int n, m;
	cin >> n >> m;

	vector<int> arr(n + 1, 0);
	for (int i = 1; i <= n; i++) {
		cin >> arr[i];
	}

	segment_tree sgt(n, arr);
	for (int i = 0, op, l, r; i < m; i++) {
		cin >> op >> l >> r;
		l++;
		r++;
		switch (op) {
		case 0:
			sgt.reset(l, r, 0, 1, n, 1);
			break;
		case 1:
			sgt.reset(l, r, 1, 1, n, 1);
			break;
		case 2:
			sgt.reversex(l, r, 1, n, 1);
			break;
		case 3:
			cout << sgt.query_sum(l, r, 1, n, 1) << endl;
			break;
		case 4:
			cout << sgt.query_maxlen(l, r, 1, n, 1) << endl;
			break;
		}
	}
	return 0;
}